package utils

import (
	"fmt"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

var hmacSampleSecret = []byte("my_eyjwt_secret")

type TokenType string

const (
	AccountType TokenType = "account"
	RefreshType TokenType = "refresh"
)

type TokenMap struct {
	Type     TokenType `json:"type"`
	Nbf      int64     `json:"nbf"`
	Username string    `json:"username"`
	UserId   int       `json:"user_id"`
	Exp      int64     `json:"exp"`
}

// 生成account token(认证令牌)
func GenerateAccountToken(username string, userId int) string {
	mapClaims := jwt.MapClaims{
		"type":     "account",
		"nbf":      time.Now().Unix(),
		"username": username,
		"userId":   userId,
		"exp":      time.Now().Add(time.Hour * 24 * 7).Unix(),
	}
	return generateJwtToken(mapClaims)
}

// 生成refresh token(刷新令牌)
func GenerateRefreshToken(username string, userId int) string {
	mapClaims := jwt.MapClaims{
		"type":     "refresh",
		"nbf":      time.Now().Unix(),
		"username": username,
		"userId":   userId,
		"exp":      time.Now().Add(time.Hour * 24 * 14).Unix(),
	}
	return generateJwtToken(mapClaims)
}

func generateJwtToken(mapClaims jwt.MapClaims) string {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, mapClaims)
	tokenString, err := token.SignedString(hmacSampleSecret)
	if err != nil {
		panic(err)
	}
	return tokenString
}

// 解析token信息
func ParseJwtToken(tokenString string) (TokenMap, error) {
	// 会自动检测nbf生效开始时间， exp为结束时间, 过期了会err
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		// Don't forget to validate the alg is what you expect:
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
		}

		return hmacSampleSecret, nil
	})
	if err != nil {
		return TokenMap{}, err
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok {
		fmt.Println(claims["type"])
		return TokenMap{
			Type:     TokenType(claims["type"].(string)),
			Nbf:      int64(claims["nbf"].(float64)),
			Username: claims["username"].(string),
			UserId:   int(claims["userId"].(float64)),
			Exp:      int64(claims["exp"].(float64)),
		}, nil
	}
	return TokenMap{}, err
}
